import java.time.Duration;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.zone.ZoneRules;

public class PhoneTip {
    private final LocalDateTime responseTime;
    private final LocalDateTime endTime;
    private final String zone = "America/New_York";
    private LocalDateTime firstTime = null;
    {
        Instant instant = Instant.ofEpochMilli(0);
        ZoneId zone = ZoneId.systemDefault();
        firstTime = LocalDateTime.ofInstant(instant, zone);
    }

    public PhoneTip(LocalDateTime responseTime, LocalDateTime endTime) {
        this.responseTime = responseTime;
        this.endTime = endTime;
    }

    public double calculateTip() throws DException{
        boolean flag = false;
        if (judgeSummerOrWinter(endTime)) {
            LocalDateTime time = LocalDateTime.of(responseTime.getYear(), responseTime.getMonth(), responseTime.getDayOfMonth(), 1, 0);
            if (endTime.isBefore(time)) {
                throw new DException("结束时间不合理");
            } else if (endTime.isBefore(responseTime)) {
                flag = true;
            }
        }
        if (responseTime.isBefore(firstTime)) {
            throw new DException("开始时间无效");
        }
        if (endTime.isBefore(firstTime)) {
            throw new DException("结束时间无效");
        }
        if (!flag && endTime.isBefore(responseTime)) {
            throw new DException("结束时间不合理");
        }
        Duration duration = Duration.between(responseTime, endTime);
        long hours = duration.toHours();
        long minutes = duration.toMillis() - duration.toMinutes() * 60000 == 0 ? duration.toMinutes() : duration.toMinutes() + 1;
        if (hours > 30) {
            throw new DException("超时");
        }
        if (flag) {
            int seconds = 60 - responseTime.getSecond() + endTime.getSecond();
            minutes = 60 - responseTime.getMinute() - 1 + endTime.getMinute()
                    + seconds /   60 + (seconds % 60 == 0 ? 0 : 1);
        }
        if (!judgeSummerOrWinter(responseTime) && judgeSummerOrWinter(endTime)) {
            minutes -= 60;
        }
        if (judgeSummerOrWinter(responseTime) && !judgeSummerOrWinter(endTime)) {
            minutes += 60;
        }
        if (minutes <= 20) {
            return minutes * 0.05;
        } else {
            return 1 + (minutes - 20) * 0.1;
        }
    }


    //判断是冬令时还是夏令时
    public boolean judgeSummerOrWinter(final LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.of(zone);
        ZoneRules rules = zoneId.getRules();
        return rules.isDaylightSavings(localDateTime.atZone(zoneId).toInstant());
    }
}